#include <unordered_set>

#include "ontatus_reverse_proxy.h"

#include "hilog_tag_wrapper.h"
#include "hilog_wrapper.h"
#include "ipc_types.h"
#include "message_parcel.h"
#include "device/device_manager_agent.h"

namespace OHOS {
namespace Storage {
namespace DistributedFile {
void RemoteMountDfsProxy::OnStatusNotify(const std::string& deviceId, uint8_t state)
{
    MessageParcel data;
    MessageParcel reply;
    MessageOption option;
    if (!data.WriteInterfaceToken(RemoteMountDfsProxy::GetDescriptor())) {
        LOGE("OnStatusNotify Write interface token failed.");
        return;
    }
    if (!data.WriteString(deviceId)) {
        LOGE("OnStatusNotify Write deviceId failed.");
        return;
    }
    if (!data.WriteUint8(state)) {
        LOGE("OnStatusNotify Write state failed.");
        return;
    }
    int32_t result = SendTransactCmd(IRemoteMountDfsListener::NOTIFY_CONNECT_CHANGED, data, reply, option);
    if (result != NO_ERROR) {
        LOGE("OnStatusNotify SendRequest fail, error: %{public}d", result);
        return;
    }
}

int32_t RemoteMountDfsProxy::SendTransactCmd(uint32_t code, MessageParcel &data,
    MessageParcel &reply, MessageOption &option)
{
    sptr<IRemoteObject> remote = Remote();
    if (remote == nullptr) {
        LOGE("remote object is nullptr.");
        return ERR_NULL_OBJECT;
    }

    int32_t ret = remote->SendRequest(code, data, reply, option);
    if (ret != NO_ERROR) {
        LOGE("SendRequest failed. code is %{public}d, ret is %{public}d.", code, ret);
        return ret;
    }
    return NO_ERROR;
}

void RemoteMountDfsProxy::ReverseDeathRecipient::SetDeathRecipient(RemoteDiedHandler handler)
{
    handler_ = std::move(handler);
}

void RemoteMountDfsProxy::ReverseDeathRecipient::OnRemoteDied(const wptr<IRemoteObject> &remote)
{
    LOGI("ReverseDeathRecipient start");
    if (handler_ != nullptr) {
        handler_(remote);
    }

    auto deviceManager = DeviceManagerAgent::GetInstance();
    auto networkIdSet = deviceManager->GetNetworkIds();
    for (auto it = networkIdSet.begin(); it != networkIdSet.end(); ++it) {
        if (*it.empty()) {
            LOGE("[ReverseDeathRecipient] networkId is null");
            continue;
        }
        // get peer deviceId by networkId
        std::string deviceId = deviceManager->GetDeviceIdByNetworkId(*it);
        if (deviceId.empty()) {
            LOGE("fail to get deviceId");
            continue;
        }
        // call storage to mkdir and mount.
        deviceManager->UMountDfsDocs(*it, deviceId, false);

        // P2POffline
        DistributedHardware::DmDeviceInfo deviceInfo{};
        std::strcpy(deviceInfo.networkId, *it.c_str());
        std::thread([=]() {
            int32_t ret = deviceManager->OnDeviceP2POffline(deviceInfo);
            LOGI("Close P2P Connection result %d", ret);
            }).detach();
    }
}

RemoteMountDfsProxy::RemoteMountDfsProxy() {
    auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
    if (samgr == nullptr) {
        LOGE("Samgr is nullptr");
        return nullptr;
    }

    auto object = samgr->CheckSystemAbility(FILEMANAGEMENT_DISTRIBUTED_FILE_DAEMON_SA_ID);
    if (object == nullptr) {
        LOGE("object == nullptr");
        return nullptr;
    }

    if (deathRecipient_ == nullptr) {
        deathRecipient_ = new (std::nothrow) DaemonDeathRecipient();
        if (deathRecipient_ == nullptr) {
            LOGE("new death recipient failed");
            return nullptr;
        }
    }
    deathRecipient_->SetDeathRecipient([](const wptr<IRemoteObject> &remote) { OnRemoteSaDied(remote); });
    if ((object->IsProxyObject()) && (!object->AddDeathRecipient(deathRecipient_))) {
        LOGE("failed to add death recipient.");
        return nullptr;
    }
}

} // namespace DistributedFile
} // namespace Storage
} // namespace OHOS